package com.alumni_circle.core.junit;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;

import java.util.Map;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author 龙小虬
 * @since 2020-08-13 19:21
 */
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
@AutoConfigureMockMvc
public abstract class BaseSecurityJunit {

    /**
     * 模拟MVC对象，通过MockMvcBuilders.webAppContextSetup(this.wac).build()初始化。
     */
    private MockMvc mockMvc;

    /**
     * 注入WebApplicationContext
     */
    @Autowired
    private WebApplicationContext wac;

    @Before
    public void setup() {
        // 在测试开始前初始化工作
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
    }


    public String securityPostTest(String username,String password,String path,Map<String,Object> map) throws Exception {
        String token = testLoginSuccessToken(username,password);

        return mockMvc.perform(MockMvcRequestBuilders.post("/"+path)
                .header("Access-Token", token)
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(JSONObject.toJSONString(map))
                )
                .andExpect(status().is(200))
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andReturn()// 返回执行请求的结果
                .getResponse()
                .getContentAsString();
    }


    public String securityGetTest(String username,String password,String path) throws Exception {

        String token = testLoginSuccessToken(username,password);

        return mockMvc.perform(MockMvcRequestBuilders.get("/"+path)
                .header("Access-Token",token)
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().is(200))
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andReturn()
                .getResponse()
                .getContentAsString();
    }


    public MvcResult testLoginSuccessMvcResult(String username,String password) throws Exception {

        // 测试登录成功
        MvcResult mvcResult = mockMvc.perform(formLogin("/login")
                .user(username)
                .password(password))
                .andReturn();
        return mvcResult;
    }

    public String testLoginSuccessToken(String username,String password) throws Exception {

        // 测试登录成功
        MvcResult mvcResult = mockMvc.perform(formLogin("/login")
                .user(username)
                .password(password))
                .andReturn();
        JSONObject jsonObject = JSON.parseObject(JSON.parseObject(mvcResult.getResponse().getContentAsString()).getString("result"));
        return jsonObject.getString("token");
    }


    public MvcResult testFormLoginFail(String username,String password) throws Exception {
        // 测试登录失败
        return mockMvc.perform(formLogin("/login").user(username).password(password)).andReturn();
    }


    public MvcResult testLogoutFail() throws Exception {
        // 测试退出登录
       return mockMvc.perform(logout("/logout")).andExpect(unauthenticated()).andReturn();
    }
}
